//! 认证模块
//! 提供统一的认证策略和中间件

use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use thiserror::Error;

/// 认证错误类型
#[derive(Error, Debug)]
pub enum AuthError {
    #[error("无效的token: {0}")]
    InvalidToken(String),
    #[error("认证失败: {0}")]
    AuthenticationFailed(String),
    #[error("权限不足: {0}")]
    InsufficientPermissions(String),
    #[error("Token过期")]
    TokenExpired,
    #[error("内部错误: {0}")]
    InternalError(String),
}

/// 认证结果
pub type AuthResult<T> = Result<T, AuthError>;

/// 认证上下文，包含用户信息和权限
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuthContext {
    pub user_id: String,
    pub username: Option<String>,
    pub roles: Vec<String>,
    pub permissions: Vec<String>,
    pub claims: HashMap<String, serde_json::Value>,
}

impl AuthContext {
    pub fn new(user_id: String) -> Self {
        Self {
            user_id,
            username: None,
            roles: Vec::new(),
            permissions: Vec::new(),
            claims: HashMap::new(),
        }
    }

    pub fn has_role(&self, role: &str) -> bool {
        self.roles.contains(&role.to_string())
    }

    pub fn has_permission(&self, permission: &str) -> bool {
        self.permissions.contains(&permission.to_string())
    }

    pub fn get_claim<T>(&self, key: &str) -> Option<T>
    where
        T: for<'de> Deserialize<'de>,
    {
        serde_json::from_value(self.claims.get(key)?.clone()).ok()
    }
}

/// 认证策略特征
pub trait AuthPolicy: Send + Sync {
    /// 验证请求并返回认证上下文
    fn authenticate(&self, request: &AuthRequest) -> AuthResult<AuthContext>;
    
    /// 检查是否有权限访问特定路由
    fn check_permission(&self, context: &AuthContext, required_policy: &str) -> AuthResult<bool>;
}

/// 认证请求信息
#[derive(Debug)]
pub struct AuthRequest {
    pub headers: HashMap<String, String>,
    pub query_params: HashMap<String, String>,
    pub path_params: HashMap<String, String>,
    pub body: Option<serde_json::Value>,
}

impl AuthRequest {
    pub fn new() -> Self {
        Self {
            headers: HashMap::new(),
            query_params: HashMap::new(),
            path_params: HashMap::new(),
            body: None,
        }
    }

    pub fn get_authorization_header(&self) -> Option<&String> {
        self.headers.get("authorization").or_else(|| self.headers.get("Authorization"))
    }

    pub fn get_bearer_token(&self) -> Option<String> {
        self.get_authorization_header()
            .and_then(|auth| {
                if auth.starts_with("Bearer ") {
                    Some(auth[7..].to_string())
                } else {
                    None
                }
            })
    }
}

/// JWT认证策略
#[cfg(feature = "jwt")]
pub struct JwtAuthPolicy {
    pub secret: String,
    pub required_claims: Vec<String>,
}

#[cfg(feature = "jwt")]
impl JwtAuthPolicy {
    pub fn new(secret: String) -> Self {
        Self {
            secret,
            required_claims: vec!["sub".to_string()], // 默认需要subject
        }
    }

    pub fn with_required_claims(mut self, claims: Vec<String>) -> Self {
        self.required_claims = claims;
        self
    }
}

#[cfg(feature = "jwt")]
impl AuthPolicy for JwtAuthPolicy {
    fn authenticate(&self, request: &AuthRequest) -> AuthResult<AuthContext> {
        use jsonwebtoken::{decode, DecodingKey, Validation, Algorithm};

        let token = request.get_bearer_token()
            .ok_or_else(|| AuthError::InvalidToken("No bearer token found".to_string()))?;

        let token_data = decode::<serde_json::Value>(
            &token,
            &DecodingKey::from_secret(self.secret.as_ref()),
            &Validation::new(Algorithm::HS256),
        )
        .map_err(|e| AuthError::InvalidToken(format!("JWT decode error: {}", e)))?;

        let claims = token_data.claims;
        
        let user_id = claims.get("sub")
            .and_then(|v| v.as_str())
            .ok_or_else(|| AuthError::InvalidToken("Missing subject claim".to_string()))?
            .to_string();

        let mut context = AuthContext::new(user_id);
        
        // 提取用户名
        if let Some(username) = claims.get("username").and_then(|v| v.as_str()) {
            context.username = Some(username.to_string());
        }

        // 提取角色
        if let Some(roles) = claims.get("roles").and_then(|v| v.as_array()) {
            context.roles = roles.iter()
                .filter_map(|v| v.as_str())
                .map(|s| s.to_string())
                .collect();
        }

        // 提取权限
        if let Some(permissions) = claims.get("permissions").and_then(|v| v.as_array()) {
            context.permissions = permissions.iter()
                .filter_map(|v| v.as_str())
                .map(|s| s.to_string())
                .collect();
        }

        // 存储所有claims
        if let serde_json::Value::Object(map) = claims {
            for (key, value) in map {
                context.claims.insert(key, value);
            }
        }

        Ok(context)
    }

    fn check_permission(&self, context: &AuthContext, required_policy: &str) -> AuthResult<bool> {
        // 简单的策略检查，可以根据需要扩展
        if required_policy.is_empty() {
            return Ok(true);
        }

        // 检查角色
        if required_policy.starts_with("role:") {
            let role = &required_policy[5..];
            return Ok(context.has_role(role));
        }

        // 检查权限
        if required_policy.starts_with("permission:") {
            let permission = &required_policy[11..];
            return Ok(context.has_permission(permission));
        }

        // 检查用户ID
        if required_policy.starts_with("user:") {
            let user_id = &required_policy[5..];
            return Ok(context.user_id == user_id);
        }

        // 默认允许
        Ok(true)
    }
}

/// 无认证策略（用于开发测试）
pub struct NoAuthPolicy;

impl AuthPolicy for NoAuthPolicy {
    fn authenticate(&self, _request: &AuthRequest) -> AuthResult<AuthContext> {
        Ok(AuthContext::new("anonymous".to_string()))
    }

    fn check_permission(&self, _context: &AuthContext, _required_policy: &str) -> AuthResult<bool> {
        Ok(true)
    }
}